import numpy as np

"""
碰撞检测器
"""


class Collider:
    def __init__(self, min_pos, max_pos):
        self.center_pos = None
        self.min_pos, self.max_pos = min_pos, max_pos

    def set_position(self, position):
        self.center_pos = position

    def contains(self, point):
        return (self.min_pos[0] <= point[0] <= self.max_pos[0] and
                self.min_pos[1] <= point[1] <= self.max_pos[1] and
                self.min_pos[2] <= point[2] <= self.max_pos[2])

    def intersects(self, other):
        """
        检测当前 AABB 是否与另一个 AABB 相交
        :param other: 另一个 AABB 对象
        :return: 如果相交返回 True，否则返回 False
        """
        # 检查每个轴上的重叠情况
        return (self.min_pos[0] <= other.max_pos[0] and
                self.max_pos[0] >= other.min_pos[0] and
                self.min_pos[1] <= other.max_pos[1] and
                self.max_pos[1] >= other.min_pos[1] and
                self.min_pos[2] <= other.max_pos[2] and
                self.max_pos[2] >= other.min_pos[2])

    def get_overlap_amount(self, other, axis):
        """
        计算在当前轴上的重叠量（带方向）
        返回值为正表示重叠，为负表示分离
        """
        overlap = min(self.max_pos[axis], other.max_pos[axis]) - max(self.min_pos[axis], other.min_pos[axis])
        return overlap

    def block_collision_processor(self, block_colliders, player_velocity):
        dx, dy, dz = player_velocity[0], player_velocity[1], player_velocity[2]
        on_ground = False

        # 逐轴处理：X → Y → Z
        for axis, delta in enumerate([dx, dy, dz]):
            if delta == 0:
                continue

            offset = np.zeros(3, dtype=np.float32)
            offset[axis] = delta
            test_aabb = Collider(self.min_pos + offset, self.max_pos + offset)

            for block in block_colliders:
                if test_aabb.intersects(block):
                    # 计算允许的最大移动距离（不穿透）
                    if delta > 0:
                        # 向右/上/前移动
                        max_allowed = block.min_pos[axis] - self.max_pos[axis]
                    else:
                        # 向左/下/后移动
                        max_allowed = block.max_pos[axis] - self.min_pos[axis]

                    # 限制速度为刚好不穿透
                    if abs(delta) > abs(max_allowed):
                        player_velocity[axis] = max_allowed - np.sign(delta) * 1e-5  # 微小偏移防止下一帧再撞

                        # 只在下落时标记为地面
                        if axis == 1 and delta < 0:
                            on_ground = True

                    break  # 每轴只处理第一个碰撞块

        return player_velocity, on_ground


class Ray:
    def __init__(self, origin, direction):
        self.origin = origin
        self.direction = direction
        self.t_min = 0.0
        self.t_max = float('inf')

    def intersects_aabb_point(self, other):

        for i in range(3):
            if abs(self.direction[i]) < 1e-6:
                if self.origin[i] < other.min_pos[i] or self.origin[i] > other.max_pos[i]:
                    return None
            else:
                ood = 1.0 / self.direction[i]
                t1 = (other.min_pos[i] - self.origin[i]) * ood
                t2 = (other.max_pos[i] - self.origin[i]) * ood
                if t1 > t2:
                    t1, t2 = t2, t1
                self.t_min = max(self.t_min, t1)
                self.t_max = min(self.t_max, t2)

                if self.t_min > self.t_max:
                    return None

        point = self.origin + self.direction * self.t_min
        return point
